﻿using System;
using TLang.Values;

namespace TLang.Ast
{
    public class IncNode : Node
    {
        private readonly Node _node;
        private readonly Node _n;
        private readonly bool _isDec;
        
        public IncNode(Node node, Node n, bool isDec, String file, int start, int end, int line, int col) : base(file, start, end, line, col)
        {
            this._node = node;
            this._n = n;
            this._isDec = isDec;
        }

        public override Value Interp(Scope s)
        {
            Value value = _node.Interp(s);
            Value n = _n.Interp(s);
            IntValue intN = n as IntValue;
            FloatValue floatN = n as FloatValue;
            if (intN == null && floatN == null)
            {
                throw new GeneralError(_n.ToString() + " must be a number");
            }
            if (value is IntValue i)
            {
                Node node = _node;
                if (node is DotNode dotNode)
                {
                    node = dotNode.Locate(s);
                }
                if (node is NameNode nameNode)
                {
                    Scope scope = s.FindDefiningScope(nameNode.Id);
                    if (intN != null)
                    {
                        IntValue v = new IntValue(_isDec ? i.Value - intN.Value : i.Value + intN.Value);
                        scope.PutValue(nameNode.Id, v);
                        return v;
                    }
                    if (floatN != null)
                    {
                        FloatValue v = new FloatValue(_isDec ? i.Value - floatN.Value : i.Value + floatN.Value);
                        scope.PutValue(nameNode.Id, v);
                        return v;
                    }
                }
                if (node is SubscriptNode subscriptNode)
                {
                    if (intN != null)
                    {
                        IntValue v = new IntValue(_isDec ? i.Value - intN.Value : i.Value + intN.Value);
                        subscriptNode.Set(v, s);
                        return v;
                    }
                    if (floatN != null)
                    {
                        FloatValue v = new FloatValue(_isDec ? i.Value - floatN.Value : i.Value + floatN.Value);
                        subscriptNode.Set(v, s);
                        return v;
                    }
                }
                if (node is IntNumNode iNode)
                {
                    if (intN != null)
                    {
                        return new IntValue(_isDec ? i.Value - intN.Value : i.Value + intN.Value);
                    }
                    if (floatN != null)
                    {
                        return new FloatValue(_isDec ? i.Value - floatN.Value : i.Value + floatN.Value);
                    }
                }
            }
            if (value is FloatValue f)
            {
                Node node = _node;
                if (node is DotNode dotNode)
                {
                    node = dotNode.Locate(s);
                }
                if (node is NameNode nameNode)
                {
                    Scope scope = s.FindDefiningScope(nameNode.Id);
                    if (intN != null)
                    {
                        FloatValue v = new FloatValue(_isDec ? f.Value - intN.Value : f.Value + intN.Value);
                        scope.PutValue(nameNode.Id, v);
                        return v;
                    }
                    if (floatN != null)
                    {
                        FloatValue v = new FloatValue(_isDec ? f.Value - floatN.Value : f.Value + floatN.Value);
                        scope.PutValue(nameNode.Id, v);
                        return v;
                    }
                }
                if (node is SubscriptNode subscriptNode)
                {
                    if (intN != null)
                    {
                        FloatValue v = new FloatValue(_isDec ? f.Value - intN.Value : f.Value + intN.Value);
                        subscriptNode.Set(v, s);
                        return v;
                    }
                    if (floatN != null)
                    {
                        FloatValue v = new FloatValue(_isDec ? f.Value - floatN.Value : f.Value + floatN.Value);
                        subscriptNode.Set(v, s);
                        return v;
                    }
                }
                if (node is FloatNumNode fNode)
                {
                    if (intN != null)
                    {
                        return new FloatValue(_isDec ? f.Value - intN.Value : f.Value + intN.Value);
                    }
                    if (floatN != null)
                    {
                        return new FloatValue(_isDec ? f.Value - floatN.Value : f.Value + floatN.Value);
                    }
                }
            }
            throw Util.GeneralError(_node.ToString() + " must be a number");
        }

        public override String ToString()
        {
            return "(" + (_isDec ? Constants.DecKeyword : Constants.IncKeyword) + " " + _node + " " + _n + ")";
        }
    }
}
